home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’96 / O Boy / Source / AEObj_pd.cp next >
Text File  |  1996-06-21  |  14KB  |  484 lines

  1. /*
  2.     AEObj_pd.cp
  3.     © Bob Boylan 1996
  4.  
  5.     Revision History
  6.     MacHack 1996    initial creation
  7. */
  8. #include "debug.h"
  9. #include "AEObj_pd.h"
  10. #include "ComputerAEObj_pd.h"
  11. #include "ComputerAETE_da.h"
  12. #include "AppAEObj_pd.h"
  13. #include "Helpers_ut.h"
  14. #include "AEBuild.h"
  15. #include "ProgressProc_hi.h"
  16. #include "FinderAppAEObj_pd.h"
  17.  
  18. #include <algo.h>
  19. #include <sstream>
  20.  
  21.  
  22. // class statics
  23. Int_32    AEObj_pd::_TimeoutinTicks = (3L * 60L);
  24.  
  25.  
  26. //    -----------------------------------------------------------------
  27. //    ctor
  28. //
  29. AEObj_pd::AEObj_pd()
  30. {
  31. }
  32. //    -----------------------------------------------------------------
  33. //    ctor
  34. //
  35. AEObj_pd::AEObj_pd(AEObj_pd * inParent, DescType inKind, Int_32 inIndex )
  36. {
  37. // get info from the parent object
  38.     _AETE = inParent->_AETE;
  39.     _AppSignature = inParent->_AppSignature;
  40.     _ObjectSpec = inParent->_ObjectSpec;
  41.  
  42. // place our object type on top of the object spec stack
  43.     ObjectSpec_da    theObjSpec;
  44.     theObjSpec._Kind = inKind;
  45.     theObjSpec._Pos = inIndex;
  46.     PushObjSpec( theObjSpec );
  47.  
  48. // update the formal name of this object
  49.     {
  50.         ostringstream    theStream( ios::in | ios::out );
  51.             theStream << GetKindName() << " " << inIndex;
  52.         _ObjectSpec.back()._FormalName = theStream.str();
  53.  
  54.     }
  55.     
  56. }
  57. //    -----------------------------------------------------------------
  58. //    ctor ... from child
  59. //
  60. AEObj_pd::AEObj_pd( AEObj_pd * inChild )
  61. {
  62. // grab the child info for ourselves
  63.     _ObjectSpec = inChild->_ObjectSpec;
  64.     _ObjectSpec.pop_back();
  65.     _AETE = inChild->_AETE;
  66.     _AppSignature = inChild->_AppSignature;
  67. }
  68.  
  69. //    -----------------------------------------------------------------
  70. //    dtor
  71. //
  72. AEObj_pd::~AEObj_pd()
  73. {
  74. }
  75. //    -----------------------------------------------------------------
  76. //    Update ... this is where we manage the data coming from the app
  77. //
  78. void
  79. AEObj_pd::Update( ProgressProc_hi &inProgressProc, Int_32 inMaxSubModels )
  80. {
  81. // inform the user as to what is happening
  82.     inProgressProc.BeginUpdate();
  83.     
  84. // first the property values
  85.     UpdatePropertyValues( inProgressProc );
  86.     
  87. // and (if not cancelled) then we do the sub models
  88.     if( inProgressProc.UserCancelled() == false )
  89.         UpdateSubModelList( inProgressProc, inMaxSubModels );
  90.         
  91. // finally, tell the user we are all done
  92.     inProgressProc.EndUpdate();
  93. }
  94. //    -----------------------------------------------------------------
  95. //    UpdateSubModelList
  96. //
  97. void
  98. AEObj_pd::UpdateSubModelList( ProgressProc_hi &inProgressProc, Int_32 inMaxSubModels)
  99. {
  100. // grab the list of sub models from the aete
  101.     vector<Elem_da>    theSubModelTypes = (*_AETE).GetElements( GetKindID() );
  102.  
  103. // and cycle thru each model type we can hold
  104.     vector<Elem_da>::iterator    theIter = theSubModelTypes.begin();
  105.     vector<Elem_da>::iterator    theLast = theSubModelTypes.end();
  106.     Int_32    theNModels;
  107.     while( (theIter != theLast) && (inProgressProc.UserCancelled() == false) )
  108.     {
  109.         // how many submodels of this kind do we have?
  110.         theNModels = GetSubModelCount( (*theIter)._ID );
  111.         Int_32    theMin = 1; // fudge for the application types - the finder doesn't consider itself a process
  112.         if( GetKindID() == cComputer ) theMin = 0;
  113.  
  114.         for( Int_32 theIndex = theMin ; theIndex <= min(inMaxSubModels, theNModels ) ; theIndex++ ) // max out at 10 for list limit reason
  115.         {
  116.             AEObj_pd *theNewObj;
  117.             // see if we are creating a regular object ... or an application object
  118.             // ... it is awkard due to the fact that the hierarchy isn't carried throughout the os
  119.             if( GetKindID() == cComputer )
  120.             {
  121.                 if( theIndex != 0 ) // yet another special case (I hate what that happens)
  122.                 {
  123.                     theNewObj = new AppAEObj_pd( this, (*theIter)._ID, theIndex );
  124.                 }
  125.                 else
  126.                 {
  127.                     theNewObj = new FinderAppAEObj_pd( this, cFinderProcess, 0 );
  128.                 }
  129.                 Clone_ut<AEObj_pd>    theClone( theNewObj ); // bind with a ref counter
  130.                 // inform the user
  131.                 inProgressProc.NewSubModel( theClone ); 
  132.             }
  133.             else
  134.             {
  135.                 // the easy case ... a real object hierarchy
  136.                 theNewObj = new AEObj_pd( this, (*theIter)._ID, theIndex );
  137.                 Clone_ut<AEObj_pd>    theClone( theNewObj ); //bind
  138.                 // inform the user
  139.                 inProgressProc.NewSubModel( theClone ); 
  140.             }
  141.         }
  142.         
  143.         ++theIter; // on to the next object kind
  144.     }
  145.  
  146. }
  147.  
  148.  
  149. //    -----------------------------------------------------------------
  150. //    GetPropertyValue
  151. //
  152. Clone_ut<PropertyValue_pd>
  153. AEObj_pd::GetPropertyValue( Prop_da &inProp )
  154. {
  155. // create the aegizmo string that represents the property we want
  156.     ostringstream    theStream( ios::in | ios::out );
  157.     theStream << "'----':obj {form:prop," <<
  158.                              "want:type(prop)," <<
  159.                              "seld:type('" << As4CharString( inProp._ID ) << "')," <<
  160.                              "from:" << GetObjAddr() << "}";
  161.     
  162.     OSErr theErr;
  163.     StAEDescriptor    theAppleEvent;
  164. // use gizmos to create the apple event
  165.      theErr = AEBuildAppleEvent( kAECoreSuite, kAEGetData,
  166.                                 GetAppAddrType(),
  167.                                 GetAppAddr(),
  168.                                 GetSizeofAppAddr(),
  169.                                 kAutoGenerateReturnID, kAnyTransactionID,
  170.                                 &theAppleEvent.mDesc, theStream.str().c_str() );
  171.     dassert( theErr == noErr );
  172.         
  173.     StAEDescriptor    theReplyAppleEvent;
  174. // and off with it
  175.     theErr = AESend( &theAppleEvent.mDesc, &theReplyAppleEvent.mDesc, kAEWaitReply,
  176.                     kAENormalPriority, _TimeoutinTicks, nil, nil );
  177.  
  178. // now see what the app gave us
  179.     StAEDescriptor    *theResult = new StAEDescriptor;
  180.     Clone_ut<StAEDescriptor>    theVal( theResult );
  181.     if( theErr == noErr )
  182.     {
  183.         theErr = AEGetParamDesc( theReplyAppleEvent, keyDirectObject, typeWildCard, &theResult->mDesc );
  184.     }
  185. // package the return value
  186.     PropertyValue_pd *thePVal = new PropertyValue_pd( inProp._ID, theVal, inProp._Name);
  187.     Clone_ut<PropertyValue_pd>    theRetVal( thePVal );
  188.     return theRetVal;
  189. }
  190.  
  191. //    -----------------------------------------------------------------
  192. //    GetName
  193. //
  194. string
  195. AEObj_pd::GetName()
  196. {
  197. // quick exit check ... is this a bozo aete?
  198.     if( IsValidAETE() == false ) return string("xxx");
  199.  
  200.  
  201. // our name starts with the formal name (e.g. Document # 1)
  202.     ostringstream    theStream( ios::in | ios::out );
  203.     theStream << GetKindName() << " # " << _ObjectSpec.back()._Pos ;
  204.  
  205. // next check and see if we have a name property
  206.     vector<Prop_da> theProps = (*_AETE).GetProperties( _ObjectSpec.back()._Kind );
  207.     Prop_da    thePropWeWant;
  208.     thePropWeWant._ID = pName;
  209.     vector<Prop_da>::iterator    theFoundItem = find( theProps.begin(), theProps.end(), thePropWeWant );
  210.  
  211. // ok, we found it ... ask the app what it is
  212.     if( theFoundItem != theProps.end() )
  213.     {
  214.         Clone_ut<PropertyValue_pd> theNamePropertyValue = GetPropertyValue( Prop_da(pName) );
  215.         _ObjectSpec.back()._Name = Asstring( *theNamePropertyValue );
  216.         theStream << string(" (") << _ObjectSpec.back()._Name << string(")");
  217.  
  218.     }
  219. // and package up the return value
  220.     return theStream.str();
  221. }
  222. //    -----------------------------------------------------------------
  223. //    GetKindName ... return the class name of this object
  224. //
  225. string
  226. AEObj_pd::GetKindName()
  227. {
  228.     return (*_AETE).GetClassName( _ObjectSpec.back()._Kind );
  229. }
  230. //    -----------------------------------------------------------------
  231. //    GetKindID ... return the class id of this object
  232. //
  233. DescType
  234. AEObj_pd::GetKindID()
  235. {
  236.     return _ObjectSpec.back()._Kind;
  237. }
  238. //    -----------------------------------------------------------------
  239. //    GetPosition
  240. //
  241. Int_32
  242. AEObj_pd::GetPosition()
  243. {
  244.     return _ObjectSpec.back()._Pos;
  245. }
  246. //    -----------------------------------------------------------------
  247. //    GetParent ... when your walking up the hierarchy
  248. //
  249. Clone_ut< AEObj_pd >
  250. AEObj_pd::GetParent()
  251. {
  252. Clone_ut<AEObj_pd>    theRetVal;
  253.  
  254.     dassert( _ObjectSpec.size() > 2 ); // check legality
  255.     AEObj_pd *theObj = nil;
  256.  
  257. // see if our parent should be an application
  258.     if( _ObjectSpec[_ObjectSpec.size()-2]._Kind == cFinderProcess )
  259.     {
  260.          theObj = new AppAEObj_pd( this );
  261.     }
  262.     else
  263.     {    // ahhh ... the easy case
  264.         theObj = new AEObj_pd( this );
  265.  
  266.     }
  267.     dassert( theObj != nil ); // just checking
  268. // package up the return value
  269.     theRetVal = Clone_ut<AEObj_pd>( theObj );
  270.     return theRetVal;
  271. }
  272. //    -----------------------------------------------------------------
  273. //    GetSibling .. great for getting the object to your left or right
  274. //
  275. Clone_ut< AEObj_pd >
  276. AEObj_pd::GetSibling( Int_32 inPositionDelta )
  277. {
  278. // first get the parent that we share
  279.     Clone_ut< AEObj_pd >    theParent;
  280.     theParent = GetParent();
  281.     AEObj_pd * theSibling;
  282.  
  283. // now see what kind of children that parent can have (remember, no one has ugly children!)
  284.     if( (*theParent).GetKindID() == cComputer )
  285.     {
  286.         if( (GetPosition() + inPositionDelta ) != 0 ) // special case for the finder/apps
  287.         {
  288.             theSibling = new AppAEObj_pd( &(*theParent), cFinderProcess, GetPosition() + inPositionDelta );
  289.         }
  290.         else
  291.         {
  292.             theSibling = new FinderAppAEObj_pd( &(*theParent), cFinderProcess, 0 );
  293.         }
  294.     }
  295.     else
  296.     {    // the easy case
  297.         theSibling = new AEObj_pd( &(*theParent), GetKindID(), GetPosition() + inPositionDelta );    
  298.     }
  299.     theSibling->GetName();    // update name for object label
  300.  
  301.  
  302. // package up the return value
  303.     Clone_ut< AEObj_pd >    theSiblingReturnValue( theSibling );
  304.     return theSiblingReturnValue;
  305. }
  306. //    -----------------------------------------------------------------
  307. //    GetSubModelCount - ask the app how many
  308. //
  309. Int_32
  310. AEObj_pd::GetSubModelCount(DescType inModelKind)
  311. {
  312. // create the aegizmo string that represents the kind we want to count
  313.     ostringstream    theStream( ios::in | ios::out );
  314.     theStream << "'----':" << GetObjAddr();
  315.     theStream << ", kocl:type(" << As4CharString(inModelKind) << ")";            
  316.         
  317. // use gizmos to create the apple event
  318.     OSErr theErr;
  319.     StAEDescriptor    theAppleEvent;
  320.      theErr = AEBuildAppleEvent( kAECoreSuite, kAECountElements,
  321.                                 GetAppAddrType(),
  322.                                 GetAppAddr(),
  323.                                 GetSizeofAppAddr(),
  324.                                 kAutoGenerateReturnID, kAnyTransactionID,
  325.                                 &theAppleEvent.mDesc, theStream.str().c_str() );
  326.     dassert( theErr == noErr );
  327.     
  328. // and off with it
  329.     StAEDescriptor    theReplyAppleEvent;
  330.     theErr = AESend( &theAppleEvent.mDesc, &theReplyAppleEvent.mDesc, kAEWaitReply,
  331.                     kAENormalPriority, _TimeoutinTicks, nil, nil );
  332.  
  333. // package up the return value
  334.     Int_32 theRetVal = 0;
  335.     if( theErr == noErr )
  336.     {
  337.     StAEDescriptor    theResult;
  338.         theErr = AEGetParamDesc( theReplyAppleEvent, keyDirectObject, typeLongInteger, &theResult.mDesc );
  339.         if( theErr == noErr )
  340.         {
  341.             theRetVal = AsInt32( theResult.mDesc );
  342.         }
  343.     }
  344.     return theRetVal;
  345. }
  346.  
  347. //    -----------------------------------------------------------------
  348. //    UpdatePropertyValues
  349. //
  350. void
  351. AEObj_pd::UpdatePropertyValues(  ProgressProc_hi &inProgressProc , DescType inPropertyID )
  352. {
  353. // get the list of properties associated with this class
  354.     vector<Prop_da>    theProps = (*_AETE).GetProperties( GetKindID() );
  355.     
  356. // and ask the app for each one
  357.     vector<Prop_da>::iterator    theIter = theProps.begin();
  358.     vector<Prop_da>::iterator    theLast = theProps.end();
  359.     while( (theIter != theLast) && (inProgressProc.UserCancelled() == false) )
  360.     {
  361.         Clone_ut<PropertyValue_pd> thePropertyValue = GetPropertyValue( *theIter );
  362.         inProgressProc.NewPropertyValue( thePropertyValue );
  363.         ++theIter;
  364.     }
  365. }
  366. //    -----------------------------------------------------------------
  367. //    GetAETE
  368. //
  369. Clone_ut< AETE_da >
  370. AEObj_pd::GetAETE()
  371. {
  372.     return _AETE;
  373. }
  374. //    -----------------------------------------------------------------
  375. //    GetObjAddr ... as a gizmo string
  376. //
  377. string
  378. AEObj_pd::GetObjAddr( )
  379. {
  380. // start at the top of the stack
  381. vector<ObjectSpec_da>::iterator    theIter = _ObjectSpec.end();
  382.  
  383.     if( _ObjectSpec.back()._Kind == typeNull ) return  string("'null'()");
  384.  
  385.     theIter--; // and work your way back up to the top (application)
  386.     return GetObjAddrR( theIter );    
  387.     
  388. }
  389. //    -----------------------------------------------------------------
  390. //    GetObjAddrR
  391. //
  392. string
  393. AEObj_pd::GetObjAddrR( vector<ObjectSpec_da>::iterator &ioIter )
  394. {
  395. string    theRetVal;
  396.     // recurse to build a gizmo string - see the gizmo docs for the details
  397.     if( ioIter->_Kind == cFinderProcess )
  398.     {
  399.         theRetVal = string("'null'()");
  400.     }
  401.     else
  402.     {
  403.         ostringstream    theStream;
  404.         theStream << "obj {form:indx,want:type('" << As4CharString( ioIter->_Kind ) + "')" +
  405.                      ",seld:" << ioIter->_Pos  <<
  406.                      ",from:";
  407.         --ioIter;
  408.         theStream << GetObjAddrR( ioIter ) + "}";
  409.         theRetVal = theStream.str();
  410.     }
  411.     return theRetVal;
  412. }
  413. //    -----------------------------------------------------------------
  414. //    GetAppAddr
  415. //
  416. void *
  417. AEObj_pd::GetAppAddr()
  418. {
  419.     return &_AppSignature;
  420. }
  421. //    -----------------------------------------------------------------
  422. //    GetAppAddrType
  423. //
  424. OSType
  425. AEObj_pd::GetAppAddrType()
  426. {
  427.     return typeApplSignature;
  428. }
  429. //    -----------------------------------------------------------------
  430. //    GetSizeofAppAddr
  431. //
  432. Int_32
  433. AEObj_pd::GetSizeofAppAddr()
  434. {
  435.     return sizeof(OSType);
  436. }
  437. //    -----------------------------------------------------------------
  438. //    PushObjSpec ... you never know when your going to change a container
  439. //
  440. void
  441. AEObj_pd::PushObjSpec( ObjectSpec_da &inObjSpec )
  442. {
  443.     _ObjectSpec.push_back( inObjSpec );
  444. }
  445. //    -----------------------------------------------------------------
  446. //    IsValidAETE
  447. //
  448. Boolean
  449. AEObj_pd::IsValidAETE()
  450. {
  451.     return !(_AETE.Isnil() );
  452. }
  453.  
  454.  
  455. //    -----------------------------------------------------------------
  456. //    GetFullName ... this is the formal name (e.g. Document #1) and any real name (e.g. "xyz") concatenated
  457. //
  458. string
  459. AEObj_pd::GetFullName()
  460. {
  461. vector<ObjectSpec_da>::iterator    theIter = _ObjectSpec.end();
  462. vector<ObjectSpec_da>::iterator    theFirst = _ObjectSpec.begin();
  463.  
  464. string    theRetVal;
  465.     do    {
  466.         theIter--; 
  467.  
  468.         theRetVal += theIter->_FormalName;
  469.         if( theIter->_Name.length() != 0 )
  470.         {
  471.             theRetVal +=  string(" (") + theIter->_Name + string(")");
  472.         }
  473.  
  474.         // only place the 'of' if it makes sense
  475.         if( theIter != theFirst )
  476.         {
  477.             theRetVal = theRetVal + " of ";
  478.         }
  479.     } while( theFirst != theIter );
  480.  
  481.     return theRetVal;
  482.     
  483. }
  484.